package cn.mesmile.emqtt.client;

import cn.mesmile.emqtt.enums.MqttQosEnum;
import cn.mesmile.emqtt.properties.MqttProperties;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * @author zb
 * @date 2021/7/11 14:49
 * @Description
 */
@Slf4j
@Component
public class EmqClient {


    private IMqttClient mqttClient;

    private final MqttProperties mqttProperties;

    private final MqttCallback mqttCallback;

    public EmqClient(MqttProperties mqttProperties, MqttCallback mqttCallback) {
        this.mqttProperties = mqttProperties;
        this.mqttCallback = mqttCallback;
    }

    @PostConstruct
    public void init(){
        MqttClientPersistence mqttClientPersistence = new MemoryPersistence();
        try {
            mqttClient = new MqttClient(mqttProperties.getBrokerUrl(), mqttProperties.getClientId(),mqttClientPersistence);
            log.info(">>>>>>>>>>> 创建mqtt客户端成功： url:{}, clientId:{}", mqttProperties.getBrokerUrl(), mqttProperties.getClientId());
        } catch (MqttException e) {
            e.printStackTrace();
            log.error(">>>>>>>>>>> 创建mqtt客户端失败：errorMsg:{}, url:{}, clientId:{}", e.getMessage(), mqttProperties.getBrokerUrl(), mqttProperties.getClientId());
        }
    }

    /**
     * 连接mqtt服务端
     */
    public void connect() {
        MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
        // 设置自动重连
        mqttConnectOptions.setAutomaticReconnect(true);
        // 是否是临时会话
        mqttConnectOptions.setCleanSession(true);
        // 设置用户名和密码
        mqttConnectOptions.setUserName(mqttProperties.getUsername());
        mqttConnectOptions.setPassword(mqttProperties.getPassword().toCharArray());
        // 设置回调
        mqttClient.setCallback(mqttCallback);
        try {
            mqttClient.connect(mqttConnectOptions);
        } catch (MqttException e) {
            e.printStackTrace();
            log.error(">>>>>>>>>>> 连接mqtt服务端失败：errorMsg:{}, mqttProperties:{}", e.getMessage(), mqttProperties.toString());
        }
    }

    /**
     * 客户端服务 退出之前，自动断开连接
     */
    @PreDestroy
    public void disConnect(){
        try {
            mqttClient.disconnect();
        } catch (MqttException e) {
            e.printStackTrace();
            log.error(">>>>>>>>>>> 连接mqtt断开服务端失败：errorMsg:{}, mqttProperties:{}", e.getMessage(), mqttProperties.toString());
        }
    }

    /**
     * 重新连接服务端
     */
    public void reConnect(){
        try {
            mqttClient.reconnect();
        } catch (MqttException e) {
            e.printStackTrace();
            log.error(">>>>>>>>>>> 重新连接mqtt服务端失败：errorMsg:{}, mqttProperties:{}", e.getMessage(), mqttProperties.toString());
        }
    }

    /**
     *  发布消息
     * @param topic
     * @param msg
     * @param qosEnum
     * @param retain
     */
    public void publish (String topic, String msg, MqttQosEnum qosEnum, boolean retain){
        MqttMessage mqttMessage = new MqttMessage();
        // 设置消息体
        mqttMessage.setPayload(msg.getBytes());
        // 设置消息发送 质量
        mqttMessage.setQos(qosEnum.value());
        // 是否是保留消息
        mqttMessage.setRetained(retain);
        // 消息id 会自动生成
//        mqttMessage.setId();
        try {
            mqttClient.publish(topic, mqttMessage);
        } catch (MqttException e) {
            e.printStackTrace();
            log.error(">>>>>>>>> 发布消息失败：errorMsg:{},topic:{},msg:{},qosEnum:{},retain:{}",
                    e.getMessage(), topic, msg, qosEnum.value(), retain);
        }
    }

    /**
     *  订阅的主题(topic)可以带  通配符
     */
    public void subscribe(String topicFilter,MqttQosEnum qosEnum){
        try {
            mqttClient.subscribe(topicFilter, qosEnum.value());
        } catch (Exception e) {
            e.printStackTrace();
            log.error(">>>>>>>>> 订阅消息失败：errorMsg:{},topic:{},qosEnum:{}",e.getMessage(), topicFilter ,qosEnum.value());
        }
    }

    /**
     * 取消订阅
     * @param topicFilter
     */
    public void unSubscribe(String topicFilter){
        try {
            mqttClient.unsubscribe(topicFilter);
        } catch (MqttException e) {
            e.printStackTrace();
            log.error(">>>>>>>>> 取消订阅消息失败：errorMsg:{},topic:{}",e.getMessage(), topicFilter);

        }
    }


}
